Basic locks are objects of type lock_t. Although functions are provided for allocating and freeing them, a basic lock is a very small object. Locks are typically allocated as global variables or as fields of structures.
Call LOCK() to seize a lock and gain possession of the resource for which it stands. Release the lock with UNLOCK(). These functions are optimized for mutual exclusion in the available hardware, and may be implemented differently in uniprocessors and multiprocessors. However, the programming and binary interface is the same in all systems.
The code in Example 9-1 illustrates the use of LOCK and UNLOCK in implementing a simple last-in-first-out (LIFO) queueing package. In these functions, the time between locking a queue head and releasing it is only a few microseconds.
Example 9-1 : LIFO Queue Using Basic Locks
typedef struct qitem { qitem *next; ...other fields... } qitem_t; typedef struct lifo { qitem *latest; lock_t grab; } lifo_t; void putlifo(lifo_t *q, qitem_t *i) { int lockpl = LOCK(&q->grab,plhi); i->next = q->latest; q->latest = i; UNLOCK(&q->grab,lockpl); } qitem_t *poplifo(lifo_t *q) { int lockpl = LOCK(&q->grab,plhi); qitem_t *ret = q->latest; q->latest = ret->next; UNLOCK(&q->grab,lockpl); return ret; }This is a typical use of basic locks: to ensure that for a brief period only one process in the system can update a queue. Basic locks are optimized for such uses, but in order to get optimal performance they are restricted to these uses. In particular, if you seize a basic lock and hold it over a function call that can sleep, the system can deadlock.